package com.cosin.dao.neo4j;

import com.cosin.model.po.NodePO;
import com.cosin.model.po.NodeWithRelationPO;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.neo4j.repository.query.Query;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Map;
import java.util.Optional;

@Repository
public interface NodeRepository extends Neo4jRepository<NodePO, Long> {

//    @CacheEvict(key = "#a0.projectId", value = "nodesOfProjects")
    NodePO save(NodePO nodePO);

    List<NodePO> findByProjectId(int projectId);
    @Query("MATCH (n:node) WHERE n.projectId = $projectId RETURN n LIMIT $limit")
    List<NodePO> findByProjectIdLimit(@Param("projectId") int projectId, @Param("limit") int limit);

    // 获取十个类型为公司的节点
    @Query("MATCH (n:node) WHERE n.group = $group AND n.projectId = $projectId RETURN n LIMIT 10")
    List<NodePO> findByGroupAndProjectIdLimit(@Param("group") String group,@Param("projectId") int projectId);

    // 查找group为公司的所有节点
    @Query("MATCH (n:node) WHERE n.group = $group AND n.projectId = $projectId RETURN n")
    List<NodePO> findByGroupAndProjectId(@Param("group") String group,@Param("projectId") int projectId);

    NodePO findByNodeIdAndProjectId(Long nodeId, int projectId);

    /**
     * 自己实现的update方法，该方法不会改变用户不可见字段，比使用save来update更加安全
     */
    @Query("MATCH (n:node {nodeId: $nodeId, projectId: $projectId}) " +
            "SET n.name = $name, n.group = $group, n.radius = $radius, " +
            "n.color = $color, n.textSize = $textSize, n.figure = $figure, " +
            "n.properties = $properties " +
            "RETURN n{.nodeId, .name, .group, .radius, .color, .textSize, .figure, .properties, .properties}")
    NodePO updateByNode(
            @Param("nodeId") long nodeId,
            @Param("projectId") int projectId,
            @Param("name") String name,
            @Param("group") String group,
            @Param("radius") int radius,
            @Param("color") String color,
            @Param("textSize") String textSize,
            @Param("figure") String figure,
            @Param("properties") String properties
    );

    @Query("MATCH (n:node {nodeId: toInteger($nodePO.nodeId), projectId: $nodePO.projectId}) DELETE n")
    void deleteByNode(@Param("nodePO") NodePO nodePO);

    @Query("MATCH (n:node {nodeId: toInteger($nodeId), projectId: $projectId}) DELETE n")
    void deleteByNode(@Param("nodeId") Long nodeId, @Param("projectId") int projectId);
//    @CacheEvict(key = "#a0.projectId", value = "nodesOfProjects")

    // 若 NodeGraphicPO 类存在且有需要，可按如下修改
    // @Query("MATCH (n:node {nodeId: $nodeGraphic.nodeId, projectId: $nodeGraphic.projectId}) " +
    //        "SET n.xAxis = $nodeGraphic.xAxis, n.yAxis = $nodeGraphic.yAxis RETURN n")
    // void updateNodeGraphic(@Param("nodeGraphic") NodeGraphicPO nodeGraphic);

//    @CacheEvict(key = "#a0.projectId", value = "nodesOfProjects")

    /**
     * 级联删除
     * @param nodePO
     */
    @Query("MATCH (n:node {nodeId: $nodePO.nodeId, projectId: $nodePO.projectId}) DETACH DELETE n")
    void cascadeDeleteNode(@Param("nodePO") NodePO nodePO);
    @Query("MATCH (n:node {nodeId: toInteger($nodeId), projectId: $projectId}) DETACH DELETE n")
    void cascadeDeleteNode(@Param("nodeId") Long nodeId, @Param("projectId") int projectId);
    @Query("WITH {nodeId: toInteger($nodePO.nodeId), projectId: $nodePO.projectId} AS params " +
            "MATCH (n:node {nodeId: params.nodeId, projectId: params.projectId}) " +
            "DETACH DELETE n " +
            "RETURN {nodeId: params.nodeId, projectId: params.projectId}")
    Optional<Map<String, Object>> cascadeDeleteNodeAndReturnParams(@Param("nodePO") NodePO nodePO);



//    @CacheEvict(key = "#a0", value = "nodesOfProjects")
    @Query("MATCH (n:node {projectId: $projectId}) DETACH DELETE n")
    void deleteByProjectId(@Param("projectId") int projectId);

    @Query("MATCH (n:node {projectId: $projectId}) WHERE n.name =~ ('(?i).*' + $name + '.*') RETURN n")
    List<NodePO> searchNodeByNameAndProjectId(@Param("name") String name, @Param("projectId") int projectId);

    @Query("MATCH (n:node) WHERE n.name =~ ('(?i).*' + $name + '.*') RETURN n")
    List<NodePO> findByNameFuzzy(@Param("name") String name);

    @Query("MATCH (n:node {projectId: $projectId}) RETURN COALESCE(MAX(n.nodeId), 0)")
    int getMaxNodeId(@Param("projectId") int projectId);

    /**
     * 根据 公司名称 和 项目Id 获取nodeId
     */
    @Query("MATCH (n:node {projectId: $projectId,name: $companyName}) RETURN n.nodeId")
    List<Long> getNodeIdByCompanyNameAndProjectId(@Param("companyName")String companyName, @Param("projectId")int projectId);

    /**
     * 根据 产品型号 和 项目Id 获取nodeId
     */
    @Query("MATCH (n:node {projectId: $projectId}) " +
            "WITH n, apoc.convert.fromJsonMap(n.properties) as props " +
            "WHERE props.型号 = $productModel " +
            "RETURN n.nodeId")
    List<Long> getNodeIdByProductModelAndProjectId(@Param("productModel") String productModel, @Param("projectId") int projectId);

    /**
     * 根据专利型号 和项目Id 获取nodeId
     */
    @Query("MATCH (n:node {projectId: $projectId}) " +
            "WITH n, apoc.convert.fromJsonMap(n.properties) as props " +
            "WHERE props.专利号 = $patentModel " +
            "RETURN n.nodeId")
    List<Long> getNodeIdByPatentModelAndProjectId(@Param("patentModel") String patentModel, @Param("projectId") int projectId);
}